package app.modules.security.business.service.role;

import app.modules.common.constant.CommonLockConstants;
import app.modules.security.business.service.SyncRbacCacheService;
import app.modules.security.constant.SecurityLockConstants;
import app.modules.security.dto.web.role.WebAssignedFunctionDTO;
import app.modules.security.persistence.dao.FunctionDAO;
import app.modules.security.persistence.dao.RoleFunctionRelationDAO;
import jasmine.framework.common.util.CheckUtil;
import jasmine.framework.common.util.CollectionUtil;
import jasmine.framework.lock.annotation.DistributedLock;
import jasmine.security.rbac.model.SecFunction;
import jasmine.security.rbac.model.SecRole;
import jasmine.security.rbac.model.SecRoleFunctionRelation;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.List;

/**
 * @author mh.z
 */
@Service
public class RoleFunctionRelationService {
    private RoleFunctionRelationDAO roleFunctionRelationDAO;
    private FunctionDAO functionDAO;
    private SyncRbacCacheService syncRbacCacheService;

    public RoleFunctionRelationService(RoleFunctionRelationDAO roleFunctionRelationDAO,
                                       FunctionDAO functionDAO, SyncRbacCacheService syncRbacCacheService) {
        this.roleFunctionRelationDAO = roleFunctionRelationDAO;
        this.functionDAO = functionDAO;
        this.syncRbacCacheService = syncRbacCacheService;
    }

    /**
     * 查询指定角色的所有已分配功能
     *
     * @param roleId
     * @return
     */
    public List<WebAssignedFunctionDTO> listWebAssignedFunctionDTOs(Long roleId) {
        List<WebAssignedFunctionDTO> recordList = roleFunctionRelationDAO.listWebAssignedFunctionDTOs(roleId);

        return recordList;
    }

    /**
     * 分配功能
     *
     * @param roleId
     * @param functionIds
     */
    @DistributedLock(category = SecurityLockConstants.LOCK_CATEGORY_ROLE_ASSIGN_FUNCTIONS, key = CommonLockConstants.LOCK_KEY_TENANT)
    @Transactional(rollbackFor = Exception.class)
    public void assignFunctions(Long roleId, List<Long> functionIds) {
        CheckUtil.notNull(roleId, "roleId null");
        CheckUtil.notNull(functionIds, "functionIds null");

        // 删除指定角色的所有功能分配关系
        roleFunctionRelationDAO.deleteByRoleId(roleId);

        if (CollectionUtil.isNotEmpty(functionIds)) {
            List<SecFunction> functionList = functionDAO.listByIds(functionIds);
            functionIds = CollectionUtil.mapToList(functionList, SecFunction::getId);

            List<SecRoleFunctionRelation> newRecordList = CollectionUtil.mapToList(functionIds, (functionId) -> {
                SecRoleFunctionRelation newRecord = new SecRoleFunctionRelation();
                newRecord.setRoleId(roleId);
                newRecord.setFunctionId(functionId);

                return newRecord;
            });

            if (CollectionUtil.isNotEmpty(newRecordList)) {
                // 保存角色和功能的分配关系
                roleFunctionRelationDAO.saveBatch(newRecordList);
            }
        }

        // 同步缓存
        syncRbacCacheService.syncFunctionsWithRoleIdCache(SecRole.class, roleId);
    }

}
